package org.kermeta.spem.activityautomation.eclipse.createkermetacompilerproject;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.kermeta.spem.activityautomation.eclipse.createkermetacompilerproject.wizards.KermetaProjectNewWizard;
import org.kermeta.spem.executioncontext.ExecutionContext;
import org.kermeta.spem.processexecution.utils.model.ModelUtils;

public class CreateKermetaCompilerProject implements IObjectActionDelegate {

	private IStructuredSelection selection;

	@Override
	public void run(IAction action) {
		// TODO Auto-generated method stub

	}

	public void run(IWorkbenchWindow window, String contextModelPath){
		//Create a new Kermeta project
		try{
			KermetaProjectNewWizard kermetaProjectNewWizard = new KermetaProjectNewWizard(contextModelPath);
			kermetaProjectNewWizard.init(window.getWorkbench(), selection);
			WizardDialog dialog = new WizardDialog(window.getShell(), kermetaProjectNewWizard);
			dialog.open();
		}catch(Exception e){
			e.printStackTrace();
		}
		//Generate visitor code
		//		ResourceSet rSet = new ResourceSetImpl();
		//		rSet.getResourceFactoryRegistry().getExtensionToFactoryMap();
		//		MainRunner.init4eclipse();
		//		rSet.getResourceFactoryRegistry().getExtensionToFactoryMap();
		//		MainRunner.init();
		//		rSet.getResourceFactoryRegistry().getExtensionToFactoryMap();
		//		MainClass m = KerRichFactory.createMainClass();
		//		m.mainOperation(contextModelPath);

		generateVisitor(contextModelPath);
	}

	public void generateVisitor(String contextModelPath)
	{
		//Get the root of the context model
		ExecutionContext executionContext = ModelUtils.getExecutionContextRoot(contextModelPath);

		//Initialize the needed variables
		String projectName = ModelUtils.getValueOfKey("project name", executionContext);
		String metamodelName = ModelUtils.getValueOfKey("model file name", executionContext);
		String compilerProjectName = ModelUtils.getValueOfKey("compiler name", executionContext);

		//Load the root of the metamodel
		ResourceSet resourceSet = new ResourceSetImpl();
		Resource ecoreResource = resourceSet.getResource(URI.createURI("platform:/resource/"+projectName+"/model/"+metamodelName+".ecore"), true);
		EPackage root = (EPackage)ecoreResource.getContents().get(0); 

		//Create files in which the code will be generated
		File visitorFile = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile()+"/"+compilerProjectName+"/src/main/kmt/"+metamodelName+"_visitors.kmt");
		File elementsFile = new File(ResourcesPlugin.getWorkspace().getRoot().getLocation().toFile()+"/"+compilerProjectName+"/src/main/kmt/"+metamodelName+"_elements.kmt");

		if (!visitorFile.exists()) {
			try {
				visitorFile.createNewFile();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		if (!elementsFile.exists()) {
			try {
				elementsFile.createNewFile();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		String contentVisitorFile = generateVisitor(root);
		String contentElementsFile = generateAspects(root);

		FileWriter elementsfw;
		try {
			elementsfw = new FileWriter(elementsFile.getAbsoluteFile());
			BufferedWriter elementsbw = new BufferedWriter(elementsfw);
			elementsbw.write(contentElementsFile);
			elementsbw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		FileWriter visitorfw;
		try {
			visitorfw = new FileWriter(visitorFile.getAbsoluteFile());
			BufferedWriter visitorbw = new BufferedWriter(visitorfw);
			visitorbw.write(contentVisitorFile);
			visitorbw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public String generateVisitor(EPackage root)
	{
		StringBuffer buf = new StringBuffer();

		buf.append("using kermeta\n"
				+ "using kermeta::io::StdIO => stdio\n"
				+ "using kermeta::standard\n"
				+ "using "+root.getName()+"\n\n\n"
				+ "package visitors {\n"
				+ "\tabstract class Visitor {\n");

		for(EClassifier c : root.getEClassifiers())
		{
			if(c instanceof EClass)
			{
				EClass cl = (EClass) c;
				buf.append("\t\toperation visit" + cl.getName() + "(e : " + cl.getName() + ") is abstract\n");
			}
		}

		for(EPackage p : root.getESubpackages()){
			buf.append("\n");

			for(EClassifier c : p.getEClassifiers()){
				if(c instanceof EClass)
				{
					EClass cl = (EClass) c;
					buf.append("\t\toperation visit" + cl.getName() + "(e : " + p.getName() + "::" + cl.getName() + ") is abstract\n");
				}
			}
		}

		buf.append("\t}\n\n\n");
		buf.append("\tclass ConcreteVisitor inherits Visitor {\n");

		for(EClassifier c : root.getEClassifiers()){
			if(c instanceof EClass){
				EClass cl = (EClass) c;
				buf.append("\t\tmethod visit" + cl.getName() + "(e : " + cl.getName() + ") is do\n"
						+ "\t\t\tstdio.writeln(\"Visiting " + cl.getName() + "\")\n"
						+ "\t\t\t//accept(self)\n"
						+ "\t\tend\n\n");
			}
		}

		for(EPackage p : root.getESubpackages()){
			buf.append("\n\n");

			for(EClassifier c : p.getEClassifiers()){
				if(c instanceof EClass)
				{
					EClass cl = (EClass) c;
					buf.append("\t\tmethod visit" + cl.getName() + "(e : " + p.getName() + "::" + cl.getName() + ") is do\n"
							+ "\t\t\tstdio.writeln(\"Visiting " + cl.getName() + "\")\n"
							+ "\t\t\t//accept(self)\n"
							+ "\t\tend\n\n");
				}
			}
		}

		buf.append("\t}\n\n"
				+ "\tabstract class Visitable {\n"
				+ "\t\toperation accept(v : Visitor) is abstract\n"
				+ "\t}\n"
				+ "}\n");		

		return buf.toString();
	}

	public String generateAspects(EPackage root)
	{
		StringBuffer buf = new StringBuffer();
		buf.append("using visitors\n\n");
		buf.append("package "+root.getName()+" {\n");

		for(EClassifier c : root.getEClassifiers()){
			if(c instanceof EClass){
				EClass cl = (EClass) c;
				buf.append("\taspect class " + cl.getName() + " inherits Visitable {\n"
						+ "\t\tmethod accept(v : Visitor) from Visitable is do\n"
						+ "\t\t\tv.visit" + cl.getName() + "(self)\n"
						+ "\t\tend\n"
						+ "\t}\n\n");		
			}
		}

		for(EPackage p : root.getESubpackages()){
			buf.append("package " + p.getName() + " {\n");

			for(EClassifier c : p.getEClassifiers()){
				if(c instanceof EClass)
				{
					EClass cl = (EClass) c;
					buf.append("\taspect class " + cl.getName() + " inherits Visitable {\n"
							+ "\t\t\tmethod accept(v : Visitor) from Visitable is do\n"
							+ "\t\t\t\tv.visit" + cl.getName() + "(self)\n"
							+ "\t\t\tend\n"
							+ "\t\t}\n\n");
				}
			}
		}

		buf.append("}\n\n");

		return buf.toString();
	}

	@Override
	public void selectionChanged(IAction action, ISelection selection) {
		this.selection =
				selection instanceof IStructuredSelection
				? (IStructuredSelection) selection
						: null;
	}

	@Override
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		// TODO Auto-generated method stub

	}

}
